﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using Autofac;
using Microsoft.Extensions.DependencyModel;

namespace CoreIOC
{
    /// <summary>
    /// 服务构建者。
    /// </summary>
    public interface IServiceBuilder
    {
        /// <summary>
        /// 服务集合。
        /// </summary>
        ContainerBuilder Services { get; set; }
    }
    /// <summary>
    /// 默认服务构建者。
    /// </summary>
    internal sealed class ServiceBuilder : IServiceBuilder
    {
        public ServiceBuilder(ContainerBuilder services)
        {
            if(services == null)
                throw new ArgumentNullException(nameof(services));
            Services = services;
        }

        #region Implementation of IServiceBuilder
        /// <summary>
        /// 服务集合。
        /// </summary>
        public ContainerBuilder Services { get; set; }

        #endregion Implementation of IServiceBuilder
    }


    public static class ContainerBuilderExtensions
    {
        private static List<Assembly> _referenceAssembly = new List<Assembly>();
        private static List<AbstractModule> _modules = new List<AbstractModule>();
        /// <summary>.
        /// 依赖注入业务模块程序集
        /// </summary>
        /// <param name="builder">ioc容器</param>
        /// <returns>返回注册模块信息</returns>
        public static IServiceBuilder RegisterServices(this IServiceBuilder builder)
        {
            try
            {
                var services = builder.Services;
               var typesList=ServiceFinder.FindFromCompileLibraries();
                foreach (var type in typesList)
                {
                    var module = type.GetTypeInfo().GetCustomAttribute<ModuleNameAttribute>();
                    if (module != null)
                    {
                        services.RegisterType(type).AsImplementedInterfaces().Named(module.ModuleName, type);
                    }
                    services.RegisterType(type).Named(type.Name, type);
                    services.RegisterType(type).Named(type.FullName, type);
                }

                //var referenceAssemblies = GetReferenceAssembly();
                //foreach (var assembly in referenceAssemblies)
                //{
                //    var types = assembly.GetTypes();
                //  //  services.RegisterAssemblyTypes(assembly).Where(t => typeof(IMrcService).GetTypeInfo().IsAssignableFrom(t) && t.IsInterface).AsImplementedInterfaces();
                //    foreach (var type in types)
                //    {
                //        var interfaceObj = type.GetInterfaces().FirstOrDefault(t => typeof(IMrcService).GetTypeInfo().IsAssignableFrom(t));
                //        if(interfaceObj != null)
                //        {
                //            var module = type.GetTypeInfo().GetCustomAttribute<ModuleNameAttribute>();
                //            if (module != null) 
                //            {
                //                services.RegisterType(type).AsImplementedInterfaces().Named(module.ModuleName, interfaceObj);
                //            }
                //            services.RegisterType(type).Named(type.Name, type);
                //            services.RegisterType(type).Named(type.FullName,type);
                //        }
                //    }
                //   // services.RegisterAssemblyTypes(assembly).Where(t => typeof(IMrcService).GetTypeInfo().IsAssignableFrom(t) && t.IsInterface).AsImplementedInterfaces();
                //}
                return builder;
            }
            catch (Exception ex)
            {
                if (ex is System.Reflection.ReflectionTypeLoadException)
                {
                    var typeLoadException = ex as ReflectionTypeLoadException;
                    var loaderExceptions = typeLoadException.LoaderExceptions;
                    throw loaderExceptions[0];
                }
                throw ex;
            }
        }


        private static List<Assembly> GetReferenceAssembly()
        {
            var refAssemblies = new List<Assembly>();
            var rootPath = AppContext.BaseDirectory;

            string[] assemblyNames = DependencyContext.Default.GetDefaultAssemblyNames().Select(p => p.Name).ToArray();
            var pattern = "^Microsoft.\\w*|^System.\\w*|^DotNetty.\\w*|^runtime.\\w*|^ZooKeeperNetEx\\w*|^StackExchange.Redis\\w*|^Consul\\w*|^Newtonsoft.Json.\\w*|^Autofac.\\w*";
            Regex notRelatedRegex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
            assemblyNames=assemblyNames.Where(name => !notRelatedRegex.IsMatch(name)).ToArray();
            foreach (var name in assemblyNames)  refAssemblies.Add(Assembly.Load(name));
            return refAssemblies;
        }

        public static void AddMicroService(this ContainerBuilder builder, Action<IServiceBuilder> option)
        {
            option.Invoke(builder.AddCoreService());
        }
        public static IServiceBuilder AddCoreService(this ContainerBuilder services)
        {
            return new ServiceBuilder(services);
        }
    }



}
